#include "refInBinFile.h"
#ifndef REF_IN_BIN_FILE
#define REF_IN_BIN_FILE
const char* check_sum = "End_of_binary_reference";
int readGenomeInBits(FILE* fp, CGenomeInBits& gInBits)
{
    int scannedItemNo = fscanf(fp, "%u\n%u\n", &(gInBits.uiSeqLength), &(gInBits.uiSeqLengthInWordSize));
    if (scannedItemNo != 2) {
        printf("%d, %u, %u", scannedItemNo, gInBits.uiSeqLength, gInBits.uiSeqLengthInWordSize);
        ERR;
    }
    unsigned int gLength = gInBits.uiSeqLength;
    unsigned int gLengthInWord = gInBits.uiSeqLengthInWordSize;
    myFread(gInBits.pLowerBits, sizeof(WORD_SIZE), gLengthInWord, fp);
    myFread(gInBits.pUpperBits, sizeof(WORD_SIZE), gLengthInWord, fp);
    unsigned int sizeInByte = size2sizeInByte(gLength);
    myFread(gInBits.pNBits->bflag, sizeof(unsigned char), sizeInByte, fp);
    return(0);
}

int saveGenomeInBits(FILE* fp, const CGenomeInBits& gInBits)
{
    fprintf(fp, "%u\n%u\n", gInBits.uiSeqLength, gInBits.uiSeqLengthInWordSize);
    unsigned int gLength = gInBits.uiSeqLength;
    unsigned int gLengthInWord = gInBits.uiSeqLengthInWordSize;
    myFwrite(gInBits.pLowerBits, sizeof(WORD_SIZE), gLengthInWord, fp);
    myFwrite(gInBits.pUpperBits, sizeof(WORD_SIZE), gLengthInWord, fp);
    unsigned int sizeInByte = size2sizeInByte(gLength);
    myFwrite(gInBits.pNBits->bflag, sizeof(unsigned char), sizeInByte, fp);
    return(0);
}

int readGenesNameVec(FILE* fp, vector<CGene>& gNameV)
{
    int noRefInVector = 0;
    if (fscanf(fp, "%d\n", &noRefInVector) == 0) {
        ERR;
    }
    gNameV.clear();
    gNameV.reserve(noRefInVector);
    CGene g;
    for (int i = 0; i < noRefInVector; i++) {
        char geneName[FILENAME_MAX];
        if (fscanf(fp, "%s\n%d\n", geneName, &(g.startIndex)) != 2) {
            ERR;
        }
        g.name = string(geneName);
        gNameV.push_back(g);
    }
    return(noRefInVector);
}

int saveGenesNameVec(FILE* fp, vector<CGene>& gNameV)
{
    int noRefInVector = (int)gNameV.size();
    fprintf(fp, "%d\n", noRefInVector);
    vector<CGene>::iterator it = gNameV.begin();
    for (; it != gNameV.end(); it++) {
        fprintf(fp, "%s\n%d\n", it->name.c_str(), it->startIndex);
    }
    return(noRefInVector);
}

int readGIndexConvertTable(FILE* fp, CGenomeNTdata& g)
{
    if (fscanf(fp, "%s\n%u\n%u\n", g.refName, &(g.iGenomeSize), &(g.iNo_of_chromosome)) != 3) {
        ERR;
        return(-1);
    }
    for (unsigned int i = 0; (i < g.iNo_of_chromosome) && (i < GENOME_CAPACITY); i++) {
        if (fscanf(fp, "%u\n", &(g.IndexCovertTable[i])) == 0) {
            ERR;
            return(-1);
        }
    }
    return(0);
}

int saveGIndexConvertTable(FILE* fp, const CGenomeNTdata& g)
{
    fprintf(fp, "%s\n", g.refName);
    fprintf(fp, "%u\n", g.iGenomeSize);
    fprintf(fp, "%u\n", g.iNo_of_chromosome);
    for (unsigned int i = 0; (i < g.iNo_of_chromosome) && (i < GENOME_CAPACITY); i++) {
        fprintf(fp, "%u\n", g.IndexCovertTable[i]);
    }
    return(0);
}

int readRefInBinFile(FILE* fp, CGenomeInBits* gInBits, CGenomeNTdata* g)
{
    if (gInBits == NULL || g == NULL) {
        ERR;
        return(1);
    } else {
        if (readGIndexConvertTable(fp, *g)) {
            ERR;
            return(1);
        }
        gInBits->allocBitStrSpace(g->iGenomeSize);
        if (readGenomeInBits(fp, *gInBits)) {
            ERR;
            return(1);
        }
        for (unsigned int i = 0; i < g->iNo_of_chromosome; i++) {
            // TODO save chromosome info
            if (g->paChromosomes[i] == NULL) {
                g->paChromosomes[i] = new CchromosomeNTdata();
            }
            CchromosomeNTdata* pChr = g->paChromosomes[i];
            if (fscanf(fp, "%s\n%u\n", pChr->caInputFileName, &(pChr->iChromosome_size)) != 2) {
                ERR;
            }
            if (readGenesNameVec(fp, pChr->geneVec.table) <= 0) {
                LOG_INFO("Info %d: ERR reading ref %d's names\n", ERROR_LOG, i);
                return(1);
            }
        }
    }
    if (!assertFile(fp, check_sum)) {
        ERR;
    }
    return(0);
}

int saveRefInBinFile(FILE* fp, const CGenomeInBits* gInBits, const CGenomeNTdata* g)
{
    if (gInBits == NULL || g == NULL) {
        ERR;
        return(1);
    } else {
        if (saveGIndexConvertTable(fp, *g)) {
            ERR;
            return(1);
        }
        if (saveGenomeInBits(fp, *gInBits)) {
            ERR;
            return(1);
        }
        for (unsigned int i = 0; i < g->iNo_of_chromosome; i++) {
            CchromosomeNTdata* pChr = g->paChromosomes[i];
            if (pChr == NULL) {
                ERR;
                return(1);
            }
            fprintf(fp, "%s\n", pChr->caInputFileName);
            fprintf(fp, "%u\n", pChr->iChromosome_size);
            if (saveGenesNameVec(fp, pChr->geneVec.table) <= 0) {
                LOG_INFO("Info %d: ERR saving ref %d's names\n", ERROR_LOG, i);
                return(1);
            }
        }
    }
    fprintf(fp, "%s\n", check_sum);
    return(0);
}
#endif
